"use strict";
/**
 * @module webview内置浏览器
 */
var __importStar = (this && this.__importStar) || function (mod) {
	if (mod && mod.__esModule) return mod;
	var result = {};
	if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k];
	result["default"] = mod;
	return result;
};
var __importDefault = (this && this.__importDefault) || function (mod) {
	return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const react_1 = __importStar(require("react"));
const react_native_1 = require("react-native");
const react_native_webview_1 = require("react-native-webview");
const uuid_1 = __importDefault(require("uuid"));
function responseweb(webview, { id }, result) {
	// 这时，web中应已注册全局函数 function m${id}(content: unknown);等待调用
	// 调用web中已注册的函数，web中收到该函数后（或超时）应反注册（删除）该全局函数,该函数如果不存在也不会抛出异常，所以这里可以不用处理函数不存在的情况
	const content = JSON.stringify(result === undefined ? null : result);
	webview.injectJavaScript(`m${id}(${JSON.stringify(content)});`); // 多一层`JSON.stringify`是为了将其变为代码的时候保证是双引号括起来的, 如content为null时， m001("null")
}
const FD_EVENTS_WEBVIEW_READY = 'fd-events-webview-ready';
const FD_EVENTS_WEBVIEW_LOAD = 'fd-events-webview-load';
const FD_EVENTS_WEBVIEW_LOADEND = 'fd-events-webview-loadend';
const FD_EVENTS_WEBVIEW_LOADSTART = 'fd-events-webview-loadstart';
const FD_EVENTS_WEBVIEW_ERROR = 'fd-events-webview-error';
const webview_name = 'webview';
class default_1 extends react_1.Component {
	constructor(props, context) {
		super(props, context);
		this.state = {
			...props,
			InnerImage: (() => {
				if (typeof this.props.progressInnerImage === 'string') {
					return { uri: this.props.progressInnerImage };
				}
				else if (typeof this.props.progressInnerImage === 'number') {
					return this.props.progressInnerImage;
				}
				else {
					return require('./images/logo.png');
				}
			})(),
			OuterImage: (() => {
				if (typeof this.props.progressOuterImage === 'string') {
					return { uri: this.props.progressOuterImage };
				}
				else if (typeof this.props.progressOuterImage === 'number') {
					return this.props.progressOuterImage;
				}
				else {
					return require('./images/circle.png');
				}
			})(),
			flag: false,
			progress: 0
		};
		this.spinValue = new react_native_1.Animated.Value(0);
		this.scaleValue = new react_native_1.Animated.Value(0);
		this.opacityValue = new react_native_1.Animated.Value(1);
	}
	componentDidMount() {
		this.spin();
		this.scale();
	}
	scale() {
		this.opacityValue.setValue(1);
		this.scaleAnim = react_native_1.Animated.sequence([
			react_native_1.Animated.timing(this.scaleValue, { toValue: 1, useNativeDriver: true, duration: 200 }),
			react_native_1.Animated.delay(500),
			react_native_1.Animated.timing(this.opacityValue, { toValue: 0, useNativeDriver: true }),
			react_native_1.Animated.timing(this.scaleValue, { toValue: 0, useNativeDriver: true, duration: 200 })
		]);
		this.scaleAnim.start(() => {
			if (this.state.progress !== 1) {
				this.scale();
			}
		});
	}
	spin() {
		this.spinValue.setValue(0);
		this.spinAnim = react_native_1.Animated.timing(this.spinValue, {
			duration: 800,
			easing: react_native_1.Easing.linear,
			toValue: 1,
			useNativeDriver: true
		});
		this.spinAnim.start(() => {
			if (this.state.progress !== 1) {
				this.spin();
			}
			else {
				// 不加延时的话logo会跟着转
				setTimeout(() => {
					this.setState({
						flag: true
					});
				}, 0);
			}
		});
	}
	fire(action, msg, timeout) {
		const id = uuid_1.default();
		const m = {
			action,
			content: msg === undefined ? null : msg,
			id,
			type: MessageType.native2web
		};
		const content = JSON.stringify(m);
		const webview = this.refs[webview_name];
		webview.injectJavaScript(`fdrn(${JSON.stringify(content)});`);
		return add(m, timeout);
	}
	render() {
		const uri = this.props.uri;
		const options = this.props;
		const fd = this.props.fd;
		if (react_native_1.Platform.OS === 'ios') {
			return react_1.default.createElement(react_native_1.View, {
				style: {
					backgroundColor: '#fff',
					flex: 1
				}
			}, this.state.progress !== 1 && react_1.default.createElement(react_native_1.ProgressViewIOS, {
				progress: this.state.progress,
				progressTintColor: this.props.progressBarColor,
				progressViewStyle: 'bar'
			}), this.renderWebView(fd, uri, options), this.state.flag === false && this.renderLoading(this.state.OuterImage, this.state.InnerImage));
		}
		else {
			if (this.state.progress === 1) {
				this.scaleAnim.stop();
				this.spinAnim.stop();
			}
			return react_1.default.createElement(react_native_1.View, {
				style: {
					backgroundColor: '#fff',
					flex: 1
				}
			}, this.state.progress !== 1 && react_1.default.createElement(react_native_1.ProgressBarAndroid, {
				color: this.props.progressBarColor,
				indeterminate: false,
				progress: this.state.progress,
				style: { height: 4 },
				styleAttr: 'Horizontal'
			}), this.renderWebView(fd, uri, options), this.state.flag === false && this.renderLoading(this.state.OuterImage, this.state.InnerImage));
		}
	}
	renderLoading(outersource, innersource) {
		const spin = this.spinValue.interpolate({
			inputRange: [0, 1],
			outputRange: ['0deg', '360deg']
		});
		return react_1.default.createElement(react_native_1.View, {
			style: {
				alignItems: 'center',
				height: '100%',
				justifyContent: 'center'
			}
		}, react_1.default.createElement(react_native_1.Animated.Image, {
			source: outersource,
			style: {
				height: 50,
				opacity: this.opacityValue,
				transform: [
					{
						rotate: spin
					},
					{
						scale: this.scaleValue
					}
				],
				width: 50
			}
		}), react_1.default.createElement(react_native_1.Animated.Image, {
			source: innersource,
			style: [
				{
					height: 40,
					opacity: this.opacityValue,
					position: 'absolute',
					width: 40
				},
				{
					transform: [
						{
							scale: this.scaleValue
						}
					]
				}
			]
		}));
	}
	renderWebView(fd, uri, options) {
		const t = this;
		const emit = fd.emit;
		return react_1.default.createElement(react_native_webview_1.WebView, {
			...options,
			allowsBackForwardNavigationGestures: true,
			onMessage: async (event) => {
				const data = JSON.parse(event.nativeEvent.data);
				const webview = this.refs[webview_name];
				switch (data.type) {
					case MessageType.webready:
						emit(fd, FD_EVENTS_WEBVIEW_READY, data); // 这时，web中应已注册全局函数 function fd(msg: Imsg);
						break;
					case MessageType.native2web:
						// 这时，web中应已注册全局函数 function fd(msg: Imsg);
						back(data);
						break;
					case MessageType.web2native:
						// 这时，web中应已注册全局函数 function m${id}(content: unknown);等待调用
						const ret = await emit(fd, data.action, data.content); // 在响应中第一个参数为fd，第二个参数即web页面发过来的数据
						responseweb(webview, data, ret);
						// 这里无法拿到页面实例，无法通过 页面实例.refs[ctl_name] 访问到webview实例
						break;
					default:
						throw new Error('Unknown message type');
				}
			},
			ref: webview_name,
			source: {
				uri
			},
			onError(...args) {
				emit(fd, FD_EVENTS_WEBVIEW_ERROR, ...args);
			},
			onLoad(...args) {
				emit(fd, FD_EVENTS_WEBVIEW_LOAD, ...args);
			},
			onLoadEnd(...args) {
				emit(fd, FD_EVENTS_WEBVIEW_LOADEND, ...args);
			},
			onLoadStart(...args) {
				emit(fd, FD_EVENTS_WEBVIEW_LOADSTART, ...args);
			},
			onLoadProgress(res) {
				t.setState({
					progress: res.nativeEvent.progress
				});
			}
		});
	}
}
default_1.defaultProps = {
	progressBarColor: 'red'
};
exports.default = default_1;
var MessageType;
(function (MessageType) {
	MessageType[MessageType["webready"] = 0] = "webready";
	MessageType[MessageType["web2native"] = 1] = "web2native";
	MessageType[MessageType["native2web"] = 2] = "native2web";
})(MessageType || (MessageType = {}));
const pool = new Map();
function add(msg, timeout) {
	const defferred = {};
	const id = msg.id;
	const handler = setTimeout(() => {
		defferred.reject(new Error('Timeout'));
	}, timeout);
	pool.set(msg.id, defferred);
	return new Promise((res, rej) => {
		defferred.resolve = (value) => {
			clearTimeout(handler);
			pool.delete(id);
			res(value);
		};
		defferred.reject = (reason) => {
			clearTimeout(handler);
			pool.delete(id);
			rej(reason);
		};
	});
}
function back({ id, content }) {
	const origin = pool.get(id);
	if (origin) {
		origin.resolve(content);
	}
}
